﻿// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "StrategyPattern.generated.h"

/**	策略模式 Strategy Pattern
 *	描述
 * 		策略模式定义了一系列的算法，并将每一个算法封装起来，而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。
 * 	套路
 * 		Context（环境类）
 * 			负责使用算法策略，其中维持了一个抽象策略类的引用实例。
 * 		Strategy（抽象策略类）
 * 			所有策略类的父类，为所支持的策略算法声明了抽象方法。它既可以是抽象类也可以是接口
 * 		ConcreteStrategy（具体策略类）
 * 			实现了在抽象策略类中声明的方法。
 * 		策略模式可以和简单工厂模式搭配使用
 * 	使用场景
 * 		如果在一个系统里面有许多类，它们之间的区别仅在于它们的行为，那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
 * 		一个系统需要动态地在几种算法中选择一种。
 * 		如果一个对象有很多的行为，如果不用恰当的模式，这些行为就只好使用多重的条件选择语句来实现。
 * 		不希望客户端知道复杂的、与算法相关的数据结构，在具体策略类中封装算法和相关的数据结构，提高算法的保密性与安全性。
 * 		示例
 * 			电影出票多种折扣方式、Steam 游戏多种折扣方式，都可以当成多种折扣策略;
 * 			多种登录方式（微信登陆、手机号码登录、邮箱登录、扫码登陆），可以视为多种登录策略
 * 			多种支付方式（微信支付、支付宝、ApplePay、银联支付），可以视为多种支付策略
 * 			不同英雄、武器的伤害计算方式，可以当作多种伤害计算策略
 * 			不同职业（种族），使用不同的武器
 * 	优缺点
 * 		优点
 * 			提供了对开闭原则的完美支持，用户可以在不修改原有系统的基础上选择具体算法或行为，也可以灵活地增加新的算法或行为。
 * 			避免了多重的if-else条件选择语句，利于系统的维护。
 * 			提供了一种算法的复用机制，不同的环境类可以方便地复用这些策略类。
 * 		缺点
 * 			客户端必须知道所有的策略类，并自行决定使用哪一个策略类。
 * 			策略模式将造成产生很多策略类，可以通过使用享元模式在一定程度上减少对象的数量。
 */

UCLASS(Abstract) // 抽象策略类 —— 武器
class MISCELLANEOUSPROJECT_API UWeapon : public UObject
{
	GENERATED_BODY()
public:
	virtual void UseWeapon() {}
};

UCLASS() // 具体策略类 —— 剑
class MISCELLANEOUSPROJECT_API USword : public UWeapon
{
	GENERATED_BODY()
public:
	virtual void UseWeapon() override
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 长剑已装备"));
	}
};

UCLASS() // 具体策略类 —— 刀
class MISCELLANEOUSPROJECT_API UMachete : public UWeapon
{
	GENERATED_BODY()
public:
	virtual void UseWeapon() override
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 大刀已装备"));
	}
};

UCLASS() // 具体策略类 —— 无武器
class MISCELLANEOUSPROJECT_API UNoWapon : public UWeapon
{
	GENERATED_BODY()
public:
	virtual void UseWeapon() override
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 赤手空拳"));
	}
};

UCLASS() // 具体策略类 —— 长弓
class MISCELLANEOUSPROJECT_API ULongbow : public UWeapon
{
	GENERATED_BODY()
public:
	virtual void UseWeapon() override
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 长弓已装备"));
	}
};

UCLASS(Abstract) // 环境抽象类 —— 角色
class MISCELLANEOUSPROJECT_API UHero : public UObject
{
	GENERATED_BODY()
public:
	// 使用策略 —— 使用武器
	virtual void UseWeapon()
	{
		if (m_pWeapon)
		{
			m_pWeapon->UseWeapon();
		}
	}

	// 更换策略 —— 更换武器
	virtual void ChangeWeapon(UWeapon* pWeapon)
	{
		m_pWeapon = pWeapon;
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 武器已更换"));
	}

protected:
	UPROPERTY()
	UWeapon* m_pWeapon;
};

UCLASS() // 环境类 —— 战士
class MISCELLANEOUSPROJECT_API UWarrior : public UHero
{
	GENERATED_BODY()
public:
	UWarrior()
	{
		// 为不同角色初始化武器
		m_pWeapon = NewObject<USword>();
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 这是一个战士"));
	}
};

UCLASS() // 环境类 —— 弓箭手
class MISCELLANEOUSPROJECT_API UArcher : public UHero
{
	GENERATED_BODY()
public:
	UArcher()
	{
		// 为不同角色初始化武器
		m_pWeapon = NewObject<ULongbow>();
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 这是一个弓箭手"));
	}
};

UCLASS()
class MISCELLANEOUSPROJECT_API AStrategyTestActor : public AActor
{
	GENERATED_BODY()
protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override
	{
		// 创建战士
		UWarrior* Warrior = NewObject<UWarrior>();
		// 使用策略 —— 使用武器
		Warrior->UseWeapon();

		// 更换策略 —— 更换武器
		Warrior->ChangeWeapon(NewObject<UMachete>());
		Warrior->UseWeapon();

		// 更换策略，不使用武器
		Warrior->ChangeWeapon(NewObject<UNoWapon>());
		Warrior->UseWeapon();

		// UE_LOG(LogTemp, Warning, TEXT("---------------------------------------"));
		// 创建弓箭手
		UArcher* Archer = NewObject<UArcher>();
		// 使用策略 —— 使用武器
		Archer->UseWeapon();

		// 更换策略，不使用武器
		Archer->ChangeWeapon(NewObject<UNoWapon>());
		Archer->UseWeapon();
	}
};
